/***************************************************************************
 *   Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com>     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "vsf.h"

vsf_err_t vsfhal_gpio_init(uint8_t index)
{
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN << index;
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_fini(uint8_t index)
{
	RCC->APB2ENR &= ~(RCC_APB2ENR_IOPAEN << index);
	RCC->APB2RSTR &= ~(RCC_APB2ENR_IOPAEN << index);
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_config(uint8_t index, uint8_t pin_idx, uint32_t mode)
{
	GPIO_TypeDef *gpio = (GPIO_TypeDef *)(GPIOA_BASE + ((uint32_t)index << 10));
	uint32_t modereg = mode & 0x0F;

	// for VSFHAL_GPIO_INPUT | VSFHAL_GPIO_PULLDOWN/VSFHAL_GPIO_PULLUP
	// reset VSFHAL_GPIO_INPUT
	if (!(mode & GPIO_CRL_MODE0) && (mode & GPIO_CRL_CNF0_1))
		modereg &= ~GPIO_CRL_CNF0_0;

	if(pin_idx < 8)
	{
		gpio->CRL = (gpio->CRL & ~(((uint32_t)0x0F) << ((pin_idx - 0) * 4))) | 
						modereg << ((pin_idx - 0) * 4);
	}
	else
	{
		gpio->CRH = (gpio->CRH & ~(((uint32_t)0x0F) << ((pin_idx - 8) * 4))) | 
						modereg << ((pin_idx - 8) * 4);
	}

	if(0x08 == modereg)
	{
		if(mode & 0x80)
			gpio->BSRR = (((uint32_t)0x01) << pin_idx);
		else
			gpio->BRR = (((uint32_t)0x01) << pin_idx);
	}
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_set(uint8_t index, uint32_t pin_mask)
{
	GPIO_TypeDef *gpio = (GPIO_TypeDef *)(GPIOA_BASE + ((uint32_t)index << 10));
	gpio->BSRR = pin_mask;
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_clear(uint8_t index, uint32_t pin_mask)
{
	GPIO_TypeDef *gpio = (GPIO_TypeDef *)(GPIOA_BASE + ((uint32_t)index << 10));
	gpio->BRR = pin_mask;
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_out(uint8_t index, uint32_t pin_mask, uint32_t value)
{
	GPIO_TypeDef *gpio = (GPIO_TypeDef *)(GPIOA_BASE + ((uint32_t)index << 10));
	gpio->BSRR = pin_mask & value;
	gpio->BRR = pin_mask & ~value;
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_in(uint8_t index, uint32_t pin_mask, uint32_t *value)
{
	GPIO_TypeDef *gpio = (GPIO_TypeDef *)(GPIOA_BASE + ((uint32_t)index << 10));
	*value = gpio->IDR & pin_mask;
	return VSFERR_NONE;
}

uint32_t vsfhal_gpio_get(uint8_t index, uint32_t pin_mask)
{
	GPIO_TypeDef *gpio = (GPIO_TypeDef *)(GPIOA_BASE + ((uint32_t)index << 10));
	return gpio->IDR & pin_mask;
}
